/**
 * Copyright &copy; 2016-2017 <a href="http://git.oschina.net/whoamien/backend_management">Backend Management</a> All rights reserved.
 */
package com.xw.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.apache.commons.lang3.StringUtils;

/**
 * The Class FileUtil.
 *
 * @author Xi Wei
 */
public class FileUtil {

	private static final int KB = 1024;

	/**
	 * 根据文件路径获取文件.
	 *
	 * @param filePath            文件路径
	 * @return 文件
	 */
	public static File getFileByPath(String filePath) {
		return StringUtil.isNullOrEmpty(filePath) ? null : new File(filePath);
	}

	/**
	 * 判断文件是否存在.
	 *
	 * @param filePath            文件路径
	 * @return {@code true}: 存在<br>
	 * 		{@code false}: 不存在
	 */
	public static boolean isFileExists(String filePath) {
		return isFileExists(getFileByPath(filePath));
	}

	/**
	 * 判断文件是否存在.
	 *
	 * @param file            文件
	 * @return {@code true}: 存在<br>
	 * 		{@code false}: 不存在
	 */
	public static boolean isFileExists(File file) {
		return file != null && file.exists();
	}

	/**
	 * 判断是否是目录.
	 *
	 * @param dirPath            目录路径
	 * @return {@code true}: 是<br>
	 * 		{@code false}: 否
	 */
	public static boolean isDir(String dirPath) {
		return isDir(getFileByPath(dirPath));
	}

	/**
	 * 判断是否是目录.
	 *
	 * @param file            文件
	 * @return {@code true}: 是<br>
	 * 		{@code false}: 否
	 */
	public static boolean isDir(File file) {
		return isFileExists(file) && file.isDirectory();
	}

	/**
	 * 判断是否是文件.
	 *
	 * @param filePath            文件路径
	 * @return {@code true}: 是<br>
	 * 		{@code false}: 否
	 */
	public static boolean isFile(String filePath) {
		return isFile(getFileByPath(filePath));
	}

	/**
	 * 判断是否是文件.
	 *
	 * @param file            文件
	 * @return {@code true}: 是<br>
	 * 		{@code false}: 否
	 */
	public static boolean isFile(File file) {
		return isFileExists(file) && file.isFile();
	}

	/**
	 * 判断目录是否存在，不存在则判断是否创建成功.
	 *
	 * @param dirPath            文件路径
	 * @return {@code true}: 存在或创建成功<br>
	 * 		{@code false}: 不存在或创建失败
	 */
	public static boolean createOrExistsDir(String dirPath) {
		return createOrExistsDir(getFileByPath(dirPath));
	}

	/**
	 * 判断目录是否存在，不存在则判断是否创建成功.
	 *
	 * @param file            文件
	 * @return {@code true}: 存在或创建成功<br>
	 * 		{@code false}: 不存在或创建失败
	 */
	public static boolean createOrExistsDir(File file) {
		// 如果存在，是目录则返回true，是文件则返回false，不存在则返回是否创建成功
		return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
	}

	/**
	 * 判断文件是否存在，不存在则判断是否创建成功.
	 *
	 * @param filePath            文件路径
	 * @return {@code true}: 存在或创建成功<br>
	 * 		{@code false}: 不存在或创建失败
	 */
	public static boolean createOrExistsFile(String filePath) {
		return createOrExistsFile(getFileByPath(filePath));
	}

	/**
	 * 判断文件是否存在，不存在则判断是否创建成功.
	 *
	 * @param file            文件
	 * @return {@code true}: 存在或创建成功<br>
	 * 		{@code false}: 不存在或创建失败
	 */
	public static boolean createOrExistsFile(File file) {
		if (file == null)
			return false;
		// 如果存在，是文件则返回true，是目录则返回false
		if (file.exists())
			return file.isFile();
		if (!createOrExistsDir(file.getParentFile()))
			return false;
		try {
			return file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 判断文件是否存在，存在则在创建之前删除.
	 *
	 * @param filePath            文件路径
	 * @return {@code true}: 创建成功<br>
	 * 		{@code false}: 创建失败
	 */
	public static boolean createFileByDeleteOldFile(String filePath) {
		return createFileByDeleteOldFile(getFileByPath(filePath));
	}

	/**
	 * 判断文件是否存在，存在则在创建之前删除.
	 *
	 * @param file            文件
	 * @return {@code true}: 创建成功<br>
	 * 		{@code false}: 创建失败
	 */
	public static boolean createFileByDeleteOldFile(File file) {
		if (file == null)
			return false;
		// 文件存在并且删除失败返回false
		if (file.exists() && file.isFile() && !file.delete())
			return false;
		// 创建目录失败返回false
		if (!createOrExistsDir(file.getParentFile()))
			return false;
		try {
			return file.createNewFile();
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 复制或移动目录
	 *
	 * @param srcDirPath
	 *            源目录路径
	 * @param destDirPath
	 *            目标目录路径
	 * @param isMove
	 *            是否移动
	 * @return {@code true}: 复制或移动成功<br>
	 * 		{@code false}: 复制或移动失败
	 */
	private static boolean copyOrMoveDir(String srcDirPath, String destDirPath, boolean isMove) {
		return copyOrMoveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath), isMove);
	}

	/**
	 * 复制或移动目录
	 *
	 * @param srcDir
	 *            源目录
	 * @param destDir
	 *            目标目录
	 * @param isMove
	 *            是否移动
	 * @return {@code true}: 复制或移动成功<br>
	 * 		{@code false}: 复制或移动失败
	 */
	private static boolean copyOrMoveDir(File srcDir, File destDir, boolean isMove) {
		if (srcDir == null || destDir == null)
			return false;
		// 如果目标目录在源目录中则返回false，看不懂的话好好想想递归怎么结束
		// srcPath : F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res
		// destPath: F:\\MyGithub\\AndroidUtilCode\\utilcode\\src\\test\\res1
		// 为防止以上这种情况出现出现误判，须分别在后面加个路径分隔符
		String srcPath = srcDir.getPath() + File.separator;
		String destPath = destDir.getPath() + File.separator;
		if (destPath.contains(srcPath))
			return false;
		// 源文件不存在或者不是目录则返回false
		if (!srcDir.exists() || !srcDir.isDirectory())
			return false;
		// 目标目录不存在返回false
		if (!createOrExistsDir(destDir))
			return false;
		File[] files = srcDir.listFiles();
		for (File file : files) {
			File oneDestFile = new File(destPath + file.getName());
			if (file.isFile()) {
				// 如果操作失败返回false
				if (!copyOrMoveFile(file, oneDestFile, isMove))
					return false;
			} else if (file.isDirectory()) {
				// 如果操作失败返回false
				if (!copyOrMoveDir(file, oneDestFile, isMove))
					return false;
			}
		}
		return !isMove || deleteDir(srcDir);
	}

	/**
	 * 复制或移动文件
	 *
	 * @param srcFilePath
	 *            源文件路径
	 * @param destFilePath
	 *            目标文件路径
	 * @param isMove
	 *            是否移动
	 * @return {@code true}: 复制或移动成功<br>
	 * 		{@code false}: 复制或移动失败
	 */
	private static boolean copyOrMoveFile(String srcFilePath, String destFilePath, boolean isMove) {
		return copyOrMoveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath), isMove);
	}

	/**
	 * 复制或移动文件
	 *
	 * @param srcFile
	 *            源文件
	 * @param destFile
	 *            目标文件
	 * @param isMove
	 *            是否移动
	 * @return {@code true}: 复制或移动成功<br>
	 * 		{@code false}: 复制或移动失败
	 */
	private static boolean copyOrMoveFile(File srcFile, File destFile, boolean isMove) {
		if (srcFile == null || destFile == null)
			return false;
		// 源文件不存在或者不是文件则返回false
		if (!srcFile.exists() || !srcFile.isFile())
			return false;
		// 目标文件存在且是文件则返回false
		if (destFile.exists() && destFile.isFile())
			return false;
		// 目标目录不存在返回false
		if (!createOrExistsDir(destFile.getParentFile()))
			return false;
		try {
			return writeFileFromIS(destFile, new FileInputStream(srcFile), false) && !(isMove && !deleteFile(srcFile));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 复制目录.
	 *
	 * @param srcDirPath            源目录路径
	 * @param destDirPath            目标目录路径
	 * @return {@code true}: 复制成功<br>
	 * 		{@code false}: 复制失败
	 */
	public static boolean copyDir(String srcDirPath, String destDirPath) {
		return copyDir(getFileByPath(srcDirPath), getFileByPath(destDirPath));
	}

	/**
	 * 复制目录.
	 *
	 * @param srcDir            源目录
	 * @param destDir            目标目录
	 * @return {@code true}: 复制成功<br>
	 * 		{@code false}: 复制失败
	 */
	public static boolean copyDir(File srcDir, File destDir) {
		return copyOrMoveDir(srcDir, destDir, false);
	}

	/**
	 * 复制文件.
	 *
	 * @param srcFilePath            源文件路径
	 * @param destFilePath            目标文件路径
	 * @return {@code true}: 复制成功<br>
	 * 		{@code false}: 复制失败
	 */
	public static boolean copyFile(String srcFilePath, String destFilePath) {
		return copyFile(getFileByPath(srcFilePath), getFileByPath(destFilePath));
	}

	/**
	 * 复制文件.
	 *
	 * @param srcFile            源文件
	 * @param destFile            目标文件
	 * @return {@code true}: 复制成功<br>
	 * 		{@code false}: 复制失败
	 */
	public static boolean copyFile(File srcFile, File destFile) {
		return copyOrMoveFile(srcFile, destFile, false);
	}

	/**
	 * 移动目录.
	 *
	 * @param srcDirPath            源目录路径
	 * @param destDirPath            目标目录路径
	 * @return {@code true}: 移动成功<br>
	 * 		{@code false}: 移动失败
	 */
	public static boolean moveDir(String srcDirPath, String destDirPath) {
		return moveDir(getFileByPath(srcDirPath), getFileByPath(destDirPath));
	}

	/**
	 * 移动目录.
	 *
	 * @param srcDir            源目录
	 * @param destDir            目标目录
	 * @return {@code true}: 移动成功<br>
	 * 		{@code false}: 移动失败
	 */
	public static boolean moveDir(File srcDir, File destDir) {
		return copyOrMoveDir(srcDir, destDir, true);
	}

	/**
	 * 移动文件.
	 *
	 * @param srcFilePath            源文件路径
	 * @param destFilePath            目标文件路径
	 * @return {@code true}: 移动成功<br>
	 * 		{@code false}: 移动失败
	 */
	public static boolean moveFile(String srcFilePath, String destFilePath) {
		return moveFile(getFileByPath(srcFilePath), getFileByPath(destFilePath));
	}

	/**
	 * 移动文件.
	 *
	 * @param srcFile            源文件
	 * @param destFile            目标文件
	 * @return {@code true}: 移动成功<br>
	 * 		{@code false}: 移动失败
	 */
	public static boolean moveFile(File srcFile, File destFile) {
		return copyOrMoveFile(srcFile, destFile, true);
	}

	/**
	 * 删除目录.
	 *
	 * @param dirPath            目录路径
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteDir(String dirPath) {
		return deleteDir(getFileByPath(dirPath));
	}

	/**
	 * 删除目录.
	 *
	 * @param dir            目录
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteDir(File dir) {
		if (dir == null)
			return false;
		// 目录不存在返回true
		if (!dir.exists())
			return true;
		// 不是目录返回false
		if (!dir.isDirectory())
			return false;
		// 现在文件存在且是文件夹
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (file.isFile()) {
					if (!deleteFile(file))
						return false;
				} else if (file.isDirectory()) {
					if (!deleteDir(file))
						return false;
				}
			}
		}
		return dir.delete();
	}

	/**
	 * 删除文件.
	 *
	 * @param srcFilePath            文件路径
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteFile(String srcFilePath) {
		return deleteFile(getFileByPath(srcFilePath));
	}

	/**
	 * 删除文件.
	 *
	 * @param file            文件
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteFile(File file) {
		return file != null && (!file.exists() || file.isFile() && file.delete());
	}

	/**
	 * 删除目录下的所有文件.
	 *
	 * @param dirPath            目录路径
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteFilesInDir(String dirPath) {
		return deleteFilesInDir(getFileByPath(dirPath));
	}

	/**
	 * 删除目录下的所有文件.
	 *
	 * @param dir            目录
	 * @return {@code true}: 删除成功<br>
	 * 		{@code false}: 删除失败
	 */
	public static boolean deleteFilesInDir(File dir) {
		if (dir == null)
			return false;
		// 目录不存在返回true
		if (!dir.exists())
			return true;
		// 不是目录返回false
		if (!dir.isDirectory())
			return false;
		// 现在文件存在且是文件夹
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (file.isFile()) {
					if (!deleteFile(file))
						return false;
				} else if (file.isDirectory()) {
					if (!deleteDir(file))
						return false;
				}
			}
		}
		return true;
	}

	/**
	 * 获取目录下所有文件.
	 *
	 * @param dirPath            目录路径
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDir(String dirPath, boolean isRecursive) {
		return listFilesInDir(getFileByPath(dirPath), isRecursive);
	}

	/**
	 * 获取目录下所有文件.
	 *
	 * @param dir            目录
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDir(File dir, boolean isRecursive) {
		if (isRecursive)
			return listFilesInDir(dir);
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		Collections.addAll(list, dir.listFiles());
		return list;
	}

	/**
	 * 获取目录下所有文件包括子目录.
	 *
	 * @param dirPath            目录路径
	 * @return 文件链表
	 */
	public static List<File> listFilesInDir(String dirPath) {
		return listFilesInDir(getFileByPath(dirPath));
	}

	/**
	 * 获取目录下所有文件包括子目录.
	 *
	 * @param dir            目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDir(File dir) {
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				list.add(file);
				if (file.isDirectory()) {
					list.addAll(listFilesInDir(file));
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录(包含子目录)下所有文件，不包含文件夹.
	 *
	 * @param dir            目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithoutFolder(File dir) {
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {

				if (file.isDirectory()) {
					list.addAll(listFilesInDir(file));
				} else {
					list.add(file);
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录下所有后缀名为suffix的文件
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dirPath            目录路径
	 * @param suffix            后缀名
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(String dirPath, String suffix, boolean isRecursive) {
		return listFilesInDirWithFilter(getFileByPath(dirPath), suffix, isRecursive);
	}

	/**
	 * 获取目录下所有后缀名为suffix的文件
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dir            目录
	 * @param suffix            后缀名
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(File dir, String suffix, boolean isRecursive) {
		if (isRecursive)
			return listFilesInDirWithFilter(dir, suffix);
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) {
					list.add(file);
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录下所有后缀名为suffix的文件包括子目录
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dirPath            目录路径
	 * @param suffix            后缀名
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(String dirPath, String suffix) {
		return listFilesInDirWithFilter(getFileByPath(dirPath), suffix);
	}

	/**
	 * 获取目录下所有后缀名为suffix的文件包括子目录
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dir            目录
	 * @param suffix            后缀名
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(File dir, String suffix) {
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (file.getName().toUpperCase().endsWith(suffix.toUpperCase())) {
					list.add(file);
				}
				if (file.isDirectory()) {
					list.addAll(listFilesInDirWithFilter(file, suffix));
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录下所有符合filter的文件.
	 *
	 * @param dirPath            目录路径
	 * @param filter            过滤器
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(String dirPath, FilenameFilter filter, boolean isRecursive) {
		return listFilesInDirWithFilter(getFileByPath(dirPath), filter, isRecursive);
	}

	/**
	 * 获取目录下所有符合filter的文件.
	 *
	 * @param dir            目录
	 * @param filter            过滤器
	 * @param isRecursive            是否递归进子目录
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(File dir, FilenameFilter filter, boolean isRecursive) {
		if (isRecursive)
			return listFilesInDirWithFilter(dir, filter);
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (filter.accept(file.getParentFile(), file.getName())) {
					list.add(file);
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录下所有符合filter的文件包括子目录.
	 *
	 * @param dirPath            目录路径
	 * @param filter            过滤器
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(String dirPath, FilenameFilter filter) {
		return listFilesInDirWithFilter(getFileByPath(dirPath), filter);
	}

	/**
	 * 获取目录下所有符合filter的文件包括子目录.
	 *
	 * @param dir            目录
	 * @param filter            过滤器
	 * @return 文件链表
	 */
	public static List<File> listFilesInDirWithFilter(File dir, FilenameFilter filter) {
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (filter.accept(file.getParentFile(), file.getName())) {
					list.add(file);
				}
				if (file.isDirectory()) {
					list.addAll(listFilesInDirWithFilter(file, filter));
				}
			}
		}
		return list;
	}

	/**
	 * 获取目录下指定文件名的文件包括子目录
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dirPath            目录路径
	 * @param fileName            文件名
	 * @return 文件链表
	 */
	public static List<File> searchFileInDir(String dirPath, String fileName) {
		return searchFileInDir(getFileByPath(dirPath), fileName);
	}

	/**
	 * 获取目录下指定文件名的文件包括子目录
	 * <p>
	 * 大小写忽略
	 * </p>.
	 *
	 * @param dir            目录
	 * @param fileName            文件名
	 * @return 文件链表
	 */
	public static List<File> searchFileInDir(File dir, String fileName) {
		if (dir == null || !isDir(dir))
			return null;
		List<File> list = new ArrayList<>();
		File[] files = dir.listFiles();
		if (files != null && files.length != 0) {
			for (File file : files) {
				if (file.getName().toUpperCase().equals(fileName.toUpperCase())) {
					list.add(file);
				}
				if (file.isDirectory()) {
					list.addAll(searchFileInDir(file, fileName));
				}
			}
		}
		return list;
	}

	/**
	 * 将输入流写入文件.
	 *
	 * @param filePath            路径
	 * @param is            输入流
	 * @param append            是否追加在文件末
	 * @return {@code true}: 写入成功<br>
	 * 		{@code false}: 写入失败
	 */
	public static boolean writeFileFromIS(String filePath, InputStream is, boolean append) {
		return writeFileFromIS(getFileByPath(filePath), is, append);
	}

	/**
	 * 将输入流写入文件.
	 *
	 * @param file            文件
	 * @param is            输入流
	 * @param append            是否追加在文件末
	 * @return {@code true}: 写入成功<br>
	 * 		{@code false}: 写入失败
	 */
	public static boolean writeFileFromIS(File file, InputStream is, boolean append) {
		if (file == null || is == null)
			return false;
		if (!createOrExistsFile(file))
			return false;
		OutputStream os = null;
		try {
			os = new BufferedOutputStream(new FileOutputStream(file, append));
			byte data[] = new byte[KB];
			int len;
			while ((len = is.read(data, 0, KB)) != -1) {
				os.write(data, 0, len);
			}
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} finally {
			closeIO(is, os);
		}
	}

	/**
	 * 将字符串写入文件.
	 *
	 * @param filePath            文件路径
	 * @param content            写入内容
	 * @param append            是否追加在文件末
	 * @return {@code true}: 写入成功<br>
	 * 		{@code false}: 写入失败
	 */
	public static boolean writeFileFromString(String filePath, String content, boolean append) {
		return writeFileFromString(getFileByPath(filePath), content, append);
	}

	/**
	 * 将字符串写入文件.
	 *
	 * @param file            文件
	 * @param content            写入内容
	 * @param append            是否追加在文件末
	 * @return {@code true}: 写入成功<br>
	 * 		{@code false}: 写入失败
	 */
	public static boolean writeFileFromString(File file, String content, boolean append) {
		if (file == null || content == null)
			return false;
		if (!createOrExistsFile(file))
			return false;
		FileWriter fileWriter = null;
		try {
			fileWriter = new FileWriter(file, append);
			fileWriter.write(content);
			return true;
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		} finally {
			closeIO(fileWriter);
		}
	}

	/**
	 * 指定编码按行读取文件到List.
	 *
	 * @param filePath            文件路径
	 * @param charsetName            编码格式
	 * @return 文件行链表
	 */
	public static List<String> readFile2List(String filePath, String charsetName) {
		return readFile2List(getFileByPath(filePath), charsetName);
	}

	/**
	 * 指定编码按行读取文件到List.
	 *
	 * @param file            文件
	 * @param charsetName            编码格式
	 * @return 文件行链表
	 */
	public static List<String> readFile2List(File file, String charsetName) {
		return readFile2List(file, 0, 0x7FFFFFFF, charsetName);
	}

	/**
	 * 指定编码按行读取文件到List.
	 *
	 * @param filePath            文件路径
	 * @param st            需要读取的开始行数
	 * @param end            需要读取的结束行数
	 * @param charsetName            编码格式
	 * @return 包含制定行的list
	 */
	public static List<String> readFile2List(String filePath, int st, int end, String charsetName) {
		return readFile2List(getFileByPath(filePath), st, end, charsetName);
	}

	/**
	 * 指定编码按行读取文件到List.
	 *
	 * @param file            文件
	 * @param st            需要读取的开始行数
	 * @param end            需要读取的结束行数
	 * @param charsetName            编码格式
	 * @return 包含从start行到end行的list
	 */
	public static List<String> readFile2List(File file, int st, int end, String charsetName) {
		if (file == null)
			return null;
		if (st > end)
			return null;
		BufferedReader reader = null;
		try {
			String line;
			int curLine = 1;
			List<String> list = new ArrayList<>();
			if (StringUtil.isNullOrEmpty(charsetName)) {
				reader = new BufferedReader(new FileReader(file));
			} else {
				reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName));
			}
			while ((line = reader.readLine()) != null) {
				if (curLine > end)
					break;
				if (st <= curLine && curLine <= end)
					list.add(line);
				++curLine;
			}
			return list;
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} finally {
			closeIO(reader);
		}
	}

	/**
	 * 指定编码按行读取文件到字符串中.
	 *
	 * @param filePath            文件路径
	 * @param charsetName            编码格式
	 * @return 字符串
	 */
	public static String readFile2String(String filePath, String charsetName) {
		return readFile2String(getFileByPath(filePath), charsetName);
	}

	/**
	 * 指定编码按行读取文件到字符串中.
	 *
	 * @param file            文件
	 * @param charsetName            编码格式
	 * @return 字符串
	 */
	public static String readFile2String(File file, String charsetName) {
		if (file == null)
			return null;
		BufferedReader reader = null;
		try {
			StringBuilder sb = new StringBuilder();
			if (StringUtil.isNullOrEmpty(charsetName)) {
				reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
			} else {
				reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), charsetName));
			}
			String line;
			while ((line = reader.readLine()) != null) {
				sb.append(line).append("\r\n");// windows系统换行为\r\n，Linux为\n
			}
			// 要去除最后的换行符
			return sb.delete(sb.length() - 2, sb.length()).toString();
		} catch (IOException e) {
			e.printStackTrace();
			return null;
		} finally {
			closeIO(reader);
		}
	}

	/**
	 * 读取文件到字符数组中.
	 *
	 * @param filePath            文件路径
	 * @return 字符数组
	 */
	public static byte[] readFile2Bytes(String filePath) {
		return readFile2Bytes(getFileByPath(filePath));
	}

	/**
	 * 读取文件到字符数组中.
	 *
	 * @param file            文件
	 * @return 字符数组
	 */
	public static byte[] readFile2Bytes(File file) {
		if (file == null)
			return null;
		try {
			return ConvertUtils.inputStream2Bytes(new FileInputStream(file));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 简单获取文件编码格式.
	 *
	 * @param filePath            文件路径
	 * @return 文件编码
	 */
	public static String getFileCharsetSimple(String filePath) {
		return getFileCharsetSimple(getFileByPath(filePath));
	}

	/**
	 * 简单获取文件编码格式.
	 *
	 * @param file            文件
	 * @return 文件编码
	 */
	public static String getFileCharsetSimple(File file) {
		int p = 0;
		InputStream is = null;
		try {
			is = new BufferedInputStream(new FileInputStream(file));
			p = (is.read() << 8) + is.read();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeIO(is);
		}
		switch (p) {
		case 0xefbb:
			return "UTF-8";
		case 0xfffe:
			return "Unicode";
		case 0xfeff:
			return "UTF-16BE";
		default:
			return "GBK";
		}
	}

	/**
	 * 获取文件行数.
	 *
	 * @param filePath            文件路径
	 * @return 文件行数
	 */
	public static int getFileLines(String filePath) {
		return getFileLines(getFileByPath(filePath));
	}

	/**
	 * 获取文件行数.
	 *
	 * @param file            文件
	 * @return 文件行数
	 */
	public static int getFileLines(File file) {
		int count = 1;
		InputStream is = null;
		try {
			is = new BufferedInputStream(new FileInputStream(file));
			byte[] buffer = new byte[KB];
			int readChars;
			while ((readChars = is.read(buffer, 0, KB)) != -1) {
				for (int i = 0; i < readChars; ++i) {
					if (buffer[i] == '\n')
						++count;
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeIO(is);
		}
		return count;
	}

	/**
	 * 关闭IO.
	 *
	 * @param closeables            closeable
	 */
	public static void closeIO(Closeable... closeables) {
		if (closeables == null)
			return;
		try {
			for (Closeable closeable : closeables) {
				if (closeable != null) {
					closeable.close();
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 获取全路径中的最长目录.
	 *
	 * @param file            文件
	 * @return filePath最长目录
	 */
	public static String getDirName(File file) {
		if (file == null)
			return null;
		return getDirName(file.getPath());
	}

	/**
	 * 获取全路径中的最长目录.
	 *
	 * @param filePath            文件路径
	 * @return filePath最长目录
	 */
	public static String getDirName(String filePath) {
		if (StringUtil.isNullOrEmpty(filePath))
			return filePath;
		int lastSep = filePath.lastIndexOf(File.separator);
		return lastSep == -1 ? "" : filePath.substring(0, lastSep + 1);
	}

	/**
	 * 获取全路径中的文件名.
	 *
	 * @param file            文件
	 * @return 文件名
	 */
	public static String getFileName(File file) {
		if (file == null)
			return null;
		return getFileName(file.getPath());
	}

	/**
	 * 获取全路径中的文件名.
	 *
	 * @param filePath            文件路径
	 * @return 文件名
	 */
	public static String getFileName(String filePath) {
		if (StringUtil.isNullOrEmpty(filePath))
			return filePath;
		int lastSep = filePath.lastIndexOf(File.separator);
		return lastSep == -1 ? filePath : filePath.substring(lastSep + 1);
	}

	/**
	 * 获取全路径中的不带拓展名的文件名.
	 *
	 * @param file            文件
	 * @return 不带拓展名的文件名
	 */
	public static String getFileNameNoExtension(File file) {
		if (file == null)
			return null;
		return getFileNameNoExtension(file.getPath());
	}

	/**
	 * 获取全路径中的不带拓展名的文件名.
	 *
	 * @param filePath            文件路径
	 * @return 不带拓展名的文件名
	 */
	public static String getFileNameNoExtension(String filePath) {
		if (StringUtil.isNullOrEmpty(filePath))
			return filePath;
		int lastPoi = filePath.lastIndexOf('.');
		int lastSep = filePath.lastIndexOf(File.separator);
		if (lastSep == -1) {
			return (lastPoi == -1 ? filePath : filePath.substring(0, lastPoi));
		}
		if (lastPoi == -1 || lastSep > lastPoi) {
			return filePath.substring(lastSep + 1);
		}
		return filePath.substring(lastSep + 1, lastPoi);
	}

	/**
	 * 获取全路径中的文件拓展名.
	 *
	 * @param file            文件
	 * @return 文件拓展名
	 */
	public static String getFileExtension(File file) {
		if (file == null)
			return null;
		return getFileExtension(file.getPath());
	}

	/**
	 * 获取全路径中的文件拓展名.
	 *
	 * @param filePath            文件路径
	 * @return 文件拓展名
	 */
	public static String getFileExtension(String filePath) {
		if (StringUtil.isNullOrEmpty(filePath))
			return filePath;
		int lastPoi = filePath.lastIndexOf('.');
		int lastSep = filePath.lastIndexOf(File.separator);
		if (lastPoi == -1 || lastSep >= lastPoi)
			return "";
		return filePath.substring(lastPoi + 1);
	}

}
